package com.lin.gameserver.handler;

import com.google.protobuf.InvalidProtocolBufferException;
import com.lin.gameserver.protobuf.CommandId;
import com.lin.gameserver.protobuf.ErrorCode;
import com.lin.gameserver.protobuf.MessageWrapper;
import com.lin.gameserver.session.GameSession;
import com.lin.gameserver.websocket.MessageLogger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 消息分发器，负责根据命令号将消息分发到对应的处理器
 */
public class MessageDispatcher {
    private static final Logger logger = LoggerFactory.getLogger(MessageDispatcher.class);
    
    // 单例实例
    private static final MessageDispatcher INSTANCE = new MessageDispatcher();
    
    // 消息处理线程池
    private final ExecutorService executor = Executors.newFixedThreadPool(
            Runtime.getRuntime().availableProcessors() * 2
    );
    
    // 命令处理器映射表
    private final Map<Integer, MessageHandler> handlerMap = new HashMap<>();
    
    /**
     * 私有构造方法，注册所有命令处理器
     */
    private MessageDispatcher() {
        // 注册心跳处理器
        registerHandler(new HeartbeatHandler());
        
        // 注册登录处理器
        registerHandler(new LoginHandler());
        
        // 可以在这里注册更多的处理器
        
        logger.info("MessageDispatcher initialized with {} handlers", handlerMap.size());
    }
    
    /**
     * 获取单例实例
     *
     * @return MessageDispatcher实例
     */
    public static MessageDispatcher getInstance() {
        return INSTANCE;
    }
    
    /**
     * 注册命令处理器
     *
     * @param handler 处理器实现
     */
    public void registerHandler(MessageHandler handler) {
        int cmdId = handler.getCommandId();
        handlerMap.put(cmdId, handler);
        logger.info("Registered handler for command: {} ({})", cmdId, CommandId.getCommandDesc(cmdId));
    }
    
    /**
     * 分发消息到对应的处理器
     *
     * @param session 游戏会话
     * @param message 原始消息数据
     */
    public void dispatch(GameSession session, byte[] message) {
        // 将消息处理放入线程池中执行，避免阻塞WebSocket线程
        executor.submit(() -> processMessage(session, message));
    }
    
    /**
     * 处理消息
     *
     * @param session 游戏会话
     * @param message 原始消息数据
     */
    private void processMessage(GameSession session, byte[] message) {
        try {
            // 解析消息
            MessageWrapper wrapper = new MessageWrapper(message);
            int cmd = wrapper.getCmd();
            long seq = wrapper.getSeq();
            
            // 查找对应的处理器
            MessageHandler handler = handlerMap.get(cmd);
            if (handler == null) {
                logger.warn("No handler found for command: {}", cmd);
                sendErrorResponse(session, cmd, seq, ErrorCode.ERROR_PARAM);
                return;
            }
            
            // 检查是否需要认证
            if (handler.requireAuthentication() && !session.isAuthenticated()) {
                logger.warn("Authentication required for command: {}, session: {}", cmd, session.getSessionId());
                sendErrorResponse(session, cmd, seq, ErrorCode.ERROR_HALL_NOT_LOGIN);
                return;
            }
            
            // 处理消息
            long startTime = System.currentTimeMillis();
            boolean success = handler.handle(session, wrapper);
            long duration = System.currentTimeMillis() - startTime;
            
            // 记录处理时间
            if (logger.isDebugEnabled()) {
                logger.debug("Command {} processed in {}ms, result: {}", 
                        cmd, duration, success ? "success" : "failed");
            }
            
            // 发送响应
            if (success) {
                sendResponse(session, wrapper.getResponseBytes());
            } else {
                logger.warn("Processing command {} failed", cmd);
                if (session.isAuthenticated()) {
                    sendResponse(session, wrapper.getResponseBytes());
                }
            }
            
        } catch (InvalidProtocolBufferException e) {
            logger.error("Failed to parse message: {}", e.getMessage());
            MessageLogger.logParseError(session.getSessionId(), message, e.getMessage());
        } catch (Exception e) {
            logger.error("Error processing message", e);
        }
    }
    
    /**
     * 发送错误响应
     *
     * @param session 游戏会话
     * @param cmd 命令号
     * @param seq 序列号
     * @param errorCode 错误码
     */
    private void sendErrorResponse(GameSession session, int cmd, long seq, int errorCode) {
        try {
            byte[] responseData = MessageWrapper.createEmptyResponse(cmd, seq, errorCode);
            sendResponse(session, responseData);
            MessageLogger.logProcessError(session.getSessionId(), cmd, 
                    "Error: " + errorCode + " (" + ErrorCode.getErrorMessage(errorCode) + ")");
        } catch (Exception e) {
            logger.error("Failed to send error response", e);
        }
    }
    
    /**
     * 发送响应
     *
     * @param session 游戏会话
     * @param responseData 响应数据
     */
    private void sendResponse(GameSession session, byte[] responseData) {
        try {
            session.sendBinaryMessage(responseData);
        } catch (Exception e) {
            logger.error("Failed to send response", e);
        }
    }
    
    /**
     * 关闭分发器
     */
    public void shutdown() {
        executor.shutdown();
    }
} 